Header file flag_set.hpp

namespace type_safe
{
    template <typename Enum>
    struct flag_set_traits;
    
    struct noflag_t;
    
    constexpr noflag_t noflag;
    
    template <typename Enum>
    using flag_combo = 'hidden';
    
    template <typename Enum>
    using flag_mask = 'hidden';
    
    template <typename Enum>
    constexpr flag_combo<Enum> combo(const flag_mask<Enum>& mask) noexcept;
    
    template <typename Enum>
    constexpr flag_mask<Enum> mask(const Enum& flag) noexcept;
    template <typename Enum>
    constexpr flag_mask<Enum> mask(const flag_combo<Enum>& combo) noexcept;
    
    template <typename Enum>
    class flag_set;
    
    template <typename Enum>
    constexpr flag_combo<Enum> combo(const flag_set<Enum>& set) noexcept;
    
    template <typename Enum>
    constexpr flag_mask<Enum> mask(const flag_set<Enum>& set) noexcept;
    
    //=== flag_set equality comparison ===//
    template <typename Enum>
    constexpr bool operator==(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;
    template <typename Enum>
    constexpr bool operator==(const flag_set<Enum>& a, noflag_t b) noexcept;
    template <typename Enum>
    constexpr bool operator==(noflag_t a, const flag_set<Enum>& b) noexcept;
    template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    constexpr bool operator==(const flag_set<Enum>& a, const FlagCombo& b) noexcept;
    template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    constexpr bool operator==(const FlagCombo& a, const flag_set<Enum>& b) noexcept;
    template <typename Enum>
    constexpr bool operator!=(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;
    template <typename Enum>
    constexpr bool operator!=(const flag_set<Enum>& a, noflag_t b) noexcept;
    template <typename Enum>
    constexpr bool operator!=(noflag_t a, const flag_set<Enum>& b) noexcept;
    template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    constexpr bool operator!=(const flag_set<Enum>& a, const FlagCombo& b) noexcept;
    template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    constexpr bool operator!=(const FlagCombo& a, const flag_set<Enum>& b) noexcept;
    
    //=== Bitwise operations for flag_set ===//
    template <typename Enum, typename FlagCombo>
    constexpr flag_set<Enum> operator|(const flag_set<Enum>& a, const FlagCombo& b);
    template <typename Enum, typename FlagCombo>
    constexpr flag_set<Enum> operator|(const FlagCombo& a, const flag_set<Enum>& b);
    template <typename Enum, typename FlagCombo>
    constexpr flag_set<Enum> operator^(const flag_set<Enum>& a, const FlagCombo& b);
    template <typename Enum, typename FlagCombo>
    constexpr flag_set<Enum> operator^(const FlagCombo& a, const flag_set<Enum>& b);
    template <typename Enum>
    constexpr flag_set<Enum> operator&(const flag_set<Enum>& a, const flag_mask<Enum>& b);
    template <typename Enum>
    constexpr flag_set<Enum> operator&(const flag_mask<Enum>& a, const flag_set<Enum>& b);
    
    //=== Bitwise and for flag_set ===//
    template <typename Enum, typename FlagCombo>
    constexpr bool operator&(const flag_set<Enum>& a, const FlagCombo& b);
    template <typename Enum, typename FlagCombo>
    constexpr bool operator&(const FlagCombo& a, const flag_set<Enum>& b);
}

template <typename Enum>
constexpr type_safe::flag_mask<Enum> operator~(const Enum& e) noexcept;

template <typename Enum>
constexpr type_safe::flag_combo<Enum> operator|(const Enum& a, const Enum& b) noexcept;

Class template type_safe::flag_set_traits

template <typename Enum>
struct flag_set_traits
: 'hidden'
{
    static constexpr std::size_t size() noexcept;
};

Traits for the enum used in a ts::flag_set.

For each enum that should be used with ts::flag_set it must provide the following interface:

The default specialization automatically works for enums that have an enumerator _flag_set_size, whose value is the number of enumerators. But you can also specialize the traits for your own enums. Enums which work with ts::flag_set are called flags.

Requires: For all specializations the enum must be contiguous starting at 0, simply don't set an explicit value to the enumerators.

Struct type_safe::noflag_t

struct noflag_t
{
    constexpr noflag_t();
};

Tag type to mark a ts::flag_set without any flags set.

Variable type_safe::noflag

constexpr noflag_t noflag;

Tag object of type ts::noflag_t.

Alias template type_safe::flag_combo

template <typename Enum>
using flag_combo = 'hidden';

Represents a combination of multiple flags.

This type is created when you write a | b, where a and b are enumerators of a flag.

Objects of this type and the flags themselves are flag combinations. You can compare two flag combinations, combine two with | and use them in ts::flag_set to set or toggle a combination of flags. Creating the complement with ~ will create a ts::flag_mask.

Requires: Enum must be a flag, i.e. valid with the ts::flag_set_traits.

Alias template type_safe::flag_mask

template <typename Enum>
using flag_mask = 'hidden';

Represents a mask of flags.

This type is created when you write ~a, where a is the enumerator of a flag.

Objects of this type are flag masks. You can compare two flag masks, combine them with & and use them in ts::flag_set to clear a combination of flags. Creating the complement with ~ will create a ts::flag_combo.

Requires: Enum must be a flag, i.e. valid with the ts::flag_set_traits.

Function template type_safe::combo

template <typename Enum>
constexpr flag_combo<Enum> combo(const flag_mask<Enum>& mask) noexcept;

Converts a flag mask to a flag combination.

Returns: The flag combination with the same value as the mask.

Notes: As you cannot use a mask to set flags in a ts::flag_set, you cannot write ~a to set all flags except a directly, you have to be explicit.

Function template type_safe::mask

(1)  template <typename Enum>
     constexpr flag_mask<Enum> mask(const Enum& flag) noexcept;

(2)  template <typename Enum>
     constexpr flag_mask<Enum> mask(const flag_combo<Enum>& combo) noexcept;

Converts a flag combination to a flag mask.

Returns: The flag mask with the same value as the flag combination.

Notes: (1) does not participate in overload resolution, unless the argument is a flagg.

Notes: As you cannot use a combination to clear flags in a ts::flag_set, you cannot write a to clear all flags except a directly, you have to be explicit.

Class template type_safe::flag_set

template <typename Enum>
class flag_set
{
public:
    constexpr flag_set() noexcept;
    constexpr flag_set(noflag_t) noexcept;
    
    template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    constexpr flag_set(const FlagCombo& combo) noexcept;
    
    template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    flag_set& operator=(const FlagCombo& combo) noexcept;
    
    flag_set& operator=(noflag_t) noexcept;
    
    void set(const Enum& flag) noexcept;
    template <typename T>
    void set(const Enum& flag, T value) noexcept;
    void set(const Enum& f, flag value) noexcept;
    
    void reset(const Enum& flag) noexcept;
    
    void toggle(const Enum& flag) noexcept;
    
    void set_all() noexcept;
    template <typename T>
    void set_all(T value) noexcept;
    void set_all(flag value) noexcept;
    void reset_all() noexcept;
    void toggle_all() noexcept;
    
    constexpr bool is_set(const Enum& flag) const noexcept;
    
    constexpr flag as_flag(const Enum& flag) const noexcept;
    
    constexpr bool any() const noexcept;
    
    constexpr bool all() const noexcept;
    
    constexpr bool none() const noexcept;
    
    template <typename T>
    constexpr T to_int() const noexcept;
    
    constexpr flag_set operator~() const noexcept;
    
    template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    flag_set& operator|=(const FlagCombo& other) noexcept;
    
    template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
    flag_set& operator^=(const FlagCombo& other) noexcept;
    
    flag_set& operator&=(const flag_mask<Enum>& other) noexcept;
};

A set of flags where each one can either be 0 or 1.

Each enumeration member represents the index of one bit.

Unlike ts::flag_combo or ts::flag_mask this does not have this semantic distinction. It is just a generic container of flags, which can be set, cleared or toggled. It can be interpreted as either a flag combination or flag mask, however.

Requires: Enum must be a flag, i.e. valid with the ts::flag_set_traits.

Default constructor type_safe::flag_set::flag_set

(1)  constexpr flag_set() noexcept;

(2)  constexpr flag_set(noflag_t) noexcept;

Effects: Creates a set where all flags are set to 0.

Function template type_safe::flag_set::flag_set

template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr flag_set(const FlagCombo& combo) noexcept;

Effects: Creates a set where all bits are set to 0 except the given ones.

Notes: This constructor only participates in overload resolution if the argument is a flag combination.

Assignment operator type_safe::flag_set::operator=

template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator=(const FlagCombo& combo) noexcept;

Effects: Same as *this = flag_set(combo).

Assignment operator type_safe::flag_set::operator=

flag_set& operator=(noflag_t) noexcept;

Effects: Same as reset_all.

Function type_safe::flag_set::set

(1)  void set(const Enum& flag) noexcept;

(2)  template <typename T>
     void set(const Enum& flag, T value) noexcept;

(3)  void set(const Enum& f, flag value) noexcept;

Effects: Sets the specified flag to 1 (1)/value (2/3).

Notes: (2) does not participate in overload resolution unless T is a boolean-like type.

Function type_safe::flag_set::reset

void reset(const Enum& flag) noexcept;

Effects: Sets the specified flag to 0.

Function type_safe::flag_set::toggle

void toggle(const Enum& flag) noexcept;

Effects: Toggles the specified flag.

Function type_safe::flag_set::set_all

(1)  void set_all() noexcept;

(2)  template <typename T>
     void set_all(T value) noexcept;

(3)  void set_all(flag value) noexcept;

(4)  void reset_all() noexcept;

(5)  void toggle_all() noexcept;

Effects: Sets/resets/toggles all flags.

Function type_safe::flag_set::is_set

constexpr bool is_set(const Enum& flag) const noexcept;

Returns: Whether or not the specified flag is set.

Function type_safe::flag_set::as_flag

constexpr flag as_flag(const Enum& flag) const noexcept;

Returns: Same as flag(is_set(flag)).

Function type_safe::flag_set::any

constexpr bool any() const noexcept;

Returns: Whether any flag is set.

Function type_safe::flag_set::all

constexpr bool all() const noexcept;

Returns: Whether all flags are set.

Function type_safe::flag_set::none

constexpr bool none() const noexcept;

Returns: Whether no flag is set.

Function template type_safe::flag_set::to_int

template <typename T>
constexpr T to_int() const noexcept;

Returns: An integer where each bit has the value of the corresponding flag.

Requires: T must be an unsigned integer type with enough bits.

Operator type_safe::flag_set::operator~

constexpr flag_set operator~() const noexcept;

Returns: A set with all the flags flipped.

Operator type_safe::flag_set::operator|=

template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator|=(const FlagCombo& other) noexcept;

Effects: Sets all flags that are set in the given flag combination.

Returns: *this

Notes: This operator does not participate in overload resolution, unless the argument is a flag combination. If you truly want to write set |= ~a, i.e. set all flags except a, use set |= combo(~a).

Operator type_safe::flag_set::operator^=

template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator^=(const FlagCombo& other) noexcept;

Effects: Toggles all flags that are set in the given flag combination.

Returns: *this

Notes: This operator does not participate in overload resolution, unless the argument is a flag combination. If you truly want to write set ^= ~a, i.e. toggle all flags except a, use set ^= combo(~a).

Operator type_safe::flag_set::operator&=

flag_set& operator&=(const flag_mask<Enum>& other) noexcept;

Effects: Clears all flags that aren't set in the given flag mask.

Returns: *this

Notes: This operator does not participate in overload resolution, unless the argument is a flag mask. If you truly want to write set &= a, i.e. clear all flags except a, use set &= mask(a).


Function template type_safe::combo

template <typename Enum>
constexpr flag_combo<Enum> combo(const flag_set<Enum>& set) noexcept;

Converts a ts::flag_set to a flag combination.

Returns: The flag combination with the same value as the set.

Function template type_safe::mask

template <typename Enum>
constexpr flag_mask<Enum> mask(const flag_set<Enum>& set) noexcept;

Converts a ts::flag_set to a flag mask.

Returns: The flag mask with the same value as the set.

flag_set equality comparison

(1)  template <typename Enum>
     constexpr bool operator==(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;

(2)  template <typename Enum>
     constexpr bool operator==(const flag_set<Enum>& a, noflag_t b) noexcept;

(3)  template <typename Enum>
     constexpr bool operator==(noflag_t a, const flag_set<Enum>& b) noexcept;

(4)  template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
     constexpr bool operator==(const flag_set<Enum>& a, const FlagCombo& b) noexcept;

(5)  template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
     constexpr bool operator==(const FlagCombo& a, const flag_set<Enum>& b) noexcept;

(6)  template <typename Enum>
     constexpr bool operator!=(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;

(7)  template <typename Enum>
     constexpr bool operator!=(const flag_set<Enum>& a, noflag_t b) noexcept;

(8)  template <typename Enum>
     constexpr bool operator!=(noflag_t a, const flag_set<Enum>& b) noexcept;

(9)  template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
     constexpr bool operator!=(const flag_set<Enum>& a, const FlagCombo& b) noexcept;

(10)  template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
     constexpr bool operator!=(const FlagCombo& a, const flag_set<Enum>& b) noexcept;

flag_set equality comparison.

Returns: Whether both flag sets have the same combination of flags set/not set.

Bitwise operations for flag_set

(1)  template <typename Enum, typename FlagCombo>
     constexpr flag_set<Enum> operator|(const flag_set<Enum>& a, const FlagCombo& b);

(2)  template <typename Enum, typename FlagCombo>
     constexpr flag_set<Enum> operator|(const FlagCombo& a, const flag_set<Enum>& b);

(3)  template <typename Enum, typename FlagCombo>
     constexpr flag_set<Enum> operator^(const flag_set<Enum>& a, const FlagCombo& b);

(4)  template <typename Enum, typename FlagCombo>
     constexpr flag_set<Enum> operator^(const FlagCombo& a, const flag_set<Enum>& b);

(5)  template <typename Enum>
     constexpr flag_set<Enum> operator&(const flag_set<Enum>& a, const flag_mask<Enum>& b);

(6)  template <typename Enum>
     constexpr flag_set<Enum> operator&(const flag_mask<Enum>& a, const flag_set<Enum>& b);

Returns: The same as a Op= b.

Bitwise and for flag_set

(1)  template <typename Enum, typename FlagCombo>
     constexpr bool operator&(const flag_set<Enum>& a, const FlagCombo& b);

(2)  template <typename Enum, typename FlagCombo>
     constexpr bool operator&(const FlagCombo& a, const flag_set<Enum>& b);

Checks whether a combination of flags is set in a.

Returns: true if all the flags set in b are also set in a, false otherwise.

Notes: These functions do not participate in overload resolution, unless FlagCombo is a flag operation.


Operator operator~

template <typename Enum>
constexpr type_safe::flag_mask<Enum> operator~(const Enum& e) noexcept;

Creates a ts::flag_mask for the single enum value.

Returns: A ts::flag_mask where all bits are set, unless the given one.

Notes: This function does not participate in overload resolution, unless Enum is an enum where the ts::flag_set_traits are specialized.

Operator operator|

template <typename Enum>
constexpr type_safe::flag_combo<Enum> operator|(const Enum& a, const Enum& b) noexcept;

Creates a ts::flag_combo from two enums.

Returns: A ts::flag_combo where the two given bits are set.

Notes: These functions do not participate in overload resolution, unless Enum is an enum where the ts::flag_set_traits are specialized.